/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sound;

import java.util.HashMap;
import java.util.Hashtable;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;

/**
 *
 * @author cottonjb
 */
public class beep {

    int hz;
    int msecs;
    int volume;
    int quietVol = 0;
    boolean addHarmonic = false;
    AudioFormat af;
    SourceDataLine sdl;
    float frequency = 44100;
    byte[] buf;
    StringBuilder sb;
    HashMap code = new HashMap(127);
    int dot = 40, dash = 120, sp = 20; // milliseconds
    char prevChar = ' ';

    public beep() {
        this(800, 200, 20, false);
    }

    public beep(int hz, int msecs, int volume, boolean addHarmonic) {
        this.hz = hz;
        this.volume = volume;
        this.addHarmonic = addHarmonic;
        this.msecs = msecs;
    }

    public void open()
            throws LineUnavailableException {
        setCodes();
        if (addHarmonic) {
            buf = new byte[2];
            af = new AudioFormat(frequency, 8, 2, true, false);
        } else {
            buf = new byte[1];
            af = new AudioFormat(frequency, 8, 1, true, false);
        }
        sdl = AudioSystem.getSourceDataLine(af);
        sdl.open(af);
    }

    public void close() {

        sdl.drain();
        sdl.stop();
        sdl.close();
    }

    public void play(int msecs)
            throws LineUnavailableException {


        sdl.start();
        for (int i = 0; i < msecs * frequency / 1000; i++) {
            double angle = i / (frequency / hz) * 2.0 * Math.PI;
            buf[0] = (byte) (Math.sin(angle) * volume);

            if (addHarmonic) {
                double angle2 = (i) / (frequency / hz) * 2.0 * Math.PI;
                buf[1] = (byte) (Math.sin(2 * angle2) * volume * 0.6);
                sdl.write(buf, 0, 2);
            } else {
                sdl.write(buf, 0, 1);
            }

        }
        //  sdl.drain();
    }

    public void quiet(int msecs)
            throws LineUnavailableException {
        sdl.start();
        for (int i = 0; i < msecs * frequency / 1000; i++) {
            double angle = i / (frequency / hz) * 2.0 * Math.PI;
            buf[0] = (byte) (Math.sin(angle) * quietVol);
            sdl.write(buf, 0, 1);

        }
        // sdl.drain();
    }

    public void playLetter(char c) {
        if (c == ' ' && c == prevChar) {//filter out multiple spaces
            return;
        }
        prevChar = c;
        sb = getCode(c);
        //say(sb);
        try {
            for (int i = 0; i < sb.length(); i++) {
                // play (dash);
                if (sb.charAt(i) == '.') {
                    play(dot);
                } else {
                    if (sb.charAt(i) == '-') {
                        play(dash);
                    } else { // space between letters or unknown letter
                        quiet(dash);
                        quiet(dash);
                    }
                }
                quiet(dot); // between dots and dashes
            }
            quiet(dash); // end of letter
            quiet(dash);

        } catch (LineUnavailableException e) {
        }
    }

    private StringBuilder getCode(char c) {
        StringBuilder sb = new StringBuilder(" ");
        try {
            sb = (StringBuilder) code.get(c);
        } catch (Exception e) {
            say("catching " + e.getLocalizedMessage());
        }
        if (sb == null) {
            sb = new StringBuilder(" ");
        }
        return sb;
    }

    private void setCodes() {
        say("Setting codes");
        code.put('a', new StringBuilder(".-"));
        code.put('b', new StringBuilder("-..."));
        code.put('c', new StringBuilder("-.-."));
        code.put('d', new StringBuilder("-.."));
        code.put('e', new StringBuilder("."));
        code.put('f', new StringBuilder("..-."));
        code.put('g', new StringBuilder("--."));
        code.put('h', new StringBuilder("...."));
        code.put('i', new StringBuilder(".."));
        code.put('j', new StringBuilder(".---"));
        code.put('k', new StringBuilder("-.-"));
        code.put('l', new StringBuilder(".-.."));
        code.put('m', new StringBuilder("--"));
        code.put('n', new StringBuilder("-."));
        code.put('o', new StringBuilder("---"));
        code.put('p', new StringBuilder(".--."));
        code.put('q', new StringBuilder("--.-"));
        code.put('r', new StringBuilder(".-."));
        code.put('s', new StringBuilder("..."));
        code.put('t', new StringBuilder("-"));
        code.put('u', new StringBuilder("..-"));
        code.put('v', new StringBuilder("...-"));
        code.put('w', new StringBuilder(".--"));
        code.put('x', new StringBuilder("-..-"));
        code.put('y', new StringBuilder("-.--"));
        code.put('z', new StringBuilder("--.."));
        code.put('A', new StringBuilder(".-"));
        code.put('B', new StringBuilder("-..."));
        code.put('C', new StringBuilder("-.-."));
        code.put('D', new StringBuilder("-.."));
        code.put('E', new StringBuilder("."));
        code.put('F', new StringBuilder("..-."));
        code.put('G', new StringBuilder("--."));
        code.put('H', new StringBuilder("...."));
        code.put('I', new StringBuilder(".."));
        code.put('J', new StringBuilder(".---"));
        code.put('K', new StringBuilder("-.-"));
        code.put('L', new StringBuilder(".-.."));
        code.put('M', new StringBuilder("--"));
        code.put('N', new StringBuilder("-."));
        code.put('O', new StringBuilder("---"));
        code.put('P', new StringBuilder(".--."));
        code.put('Q', new StringBuilder("--.-"));
        code.put('R', new StringBuilder(".-."));
        code.put('S', new StringBuilder("..."));
        code.put('T', new StringBuilder("-"));
        code.put('U', new StringBuilder("..-"));
        code.put('V', new StringBuilder("...-"));
        code.put('W', new StringBuilder(".--"));
        code.put('X', new StringBuilder("-..-"));
        code.put('Y', new StringBuilder("-.--"));
        code.put('Z', new StringBuilder("--.."));
        code.put('1', new StringBuilder(".----"));
        code.put('2', new StringBuilder("..---"));
        code.put('3', new StringBuilder("...--"));
        code.put('4', new StringBuilder("....-"));
        code.put('5', new StringBuilder("....."));
        code.put('6', new StringBuilder("-...."));
        code.put('7', new StringBuilder("--..."));
        code.put('8', new StringBuilder("---.."));
        code.put('9', new StringBuilder("----."));
        code.put('0', new StringBuilder("-----"));
        code.put('.', new StringBuilder(".-.-.-"));
        code.put(',', new StringBuilder("--..--"));
        code.put('/', new StringBuilder("-..--"));
        code.put('?', new StringBuilder("..--.."));
        code.put('-', new StringBuilder("-...-"));
        code.put('=', new StringBuilder(".-.-."));
        code.put(' ', new StringBuilder(" "));
    }

    public int getDot() {
        return dot;
    }

    public void setDot(int dot) {
        this.dot = dot;
    }

    public int getDash() {
        return dash;
    }

    public void setDash(int dash) {
        this.dash = dash;
    }

    public int getSp() {
        return sp;
    }

    public void setSp(int sp) {
        this.sp = sp;
    }

    private static void say(String s) {
        System.out.println(s);
    }

    private static void say(StringBuilder s) {
        System.out.println(s);
    }

    private static void say(char c) {
        System.out.print(c);

    }
}
